package com.wswy.wyjk.core.location;

import android.Manifest.permission;
import android.content.Context;
import android.location.Location;
import android.support.v4.app.FragmentActivity;
import android.text.TextUtils;
import com.amap.api.services.core.AMapException;
import com.amap.api.services.district.DistrictItem;
import com.amap.api.services.district.DistrictResult;
import com.amap.api.services.district.DistrictSearch;
import com.amap.api.services.district.DistrictSearchQuery;
import com.blankj.utilcode.util.PermissionUtils;
import com.raft.framework.utils.RxUtils;
import com.raft.framework.utils.optional.Optional;
import com.tbruyelle.rxpermissions2.RxPermissions;
import com.wswy.wyjk.model.AmapCityModel;
import com.wswy.wyjk.utils.JsonKit;
import com.wswy.wyjk.utils.Tools;
import io.reactivex.Single;
import io.reactivex.functions.Predicate;
import io.reactivex.observers.ResourceObserver;
import timber.log.Timber;

import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicReference;

public class LocManager {

  private static final String LAST_LOCATION = "user_loc_cache";


  private static LocManager sLocManager;

  public static LocManager getInstance(){
    if(sLocManager == null){
      synchronized (LocManager.class){
        if(sLocManager == null){
          sLocManager = new LocManager();
        }
      }
    }

    return sLocManager;
  }


  private Context context;

  private LocationModel currentLocation;

  private boolean isLoading = false;

  private LocManager() {
  }

  public LocManager init(Context context){
    this.context = context;

    return this;
  }

  public boolean hasPermission(){
    return PermissionUtils.isGranted(permission.ACCESS_FINE_LOCATION);
  }

  public boolean isLoading() {
    return isLoading;
  }


  public void requestAndLoad(FragmentActivity activity, final OnRequestLocationCallback callback){
    new RxPermissions(activity).request(permission.ACCESS_FINE_LOCATION).subscribe(
        new ResourceObserver<Boolean>() {
          @Override
          public void onNext(Boolean aBoolean) {
            if (aBoolean){
              loadLocation(callback);
            }else {
              //请求拒绝
              if (callback != null){
                callback.onError("没有权限");
              }
            }

          }

          @Override
          public void onError(Throwable e) {

          }

          @Override
          public void onComplete() {

          }
        });
  }

  public void loadLocation(){
    loadLocation(null);
  }


  public void loadLocation(final OnRequestLocationCallback callback){

    if(!isLoading && PermissionUtils.isGranted(permission.ACCESS_FINE_LOCATION)) {
      isLoading = true;
      LocationLoader.load(context, new LocationLoader.OnLocationCallback() {
        @Override
        public void onLoaded(LocationModel locationModel) {
          isLoading = false;
          if(locationModel != null && !TextUtils.isEmpty(locationModel.province) && !TextUtils.isEmpty(locationModel.province)){
            currentLocation = locationModel;

            Tools.getCache().put(LAST_LOCATION,JsonKit.GSON.toJson(locationModel));

            if (callback != null){
              callback.onGetLocation(locationModel);
            }

            onGetLoc(locationModel);
          }
        }
      });

    }
  }




  private void onGetLoc(LocationModel model){
    //RxBus.getDefault().postWithCode(InternalMsgCode.CODE_GET_LOCATION,model);
  }

  private LocationModel getFromCache(){
    String json = Tools.getCache().getString(LAST_LOCATION);
    if (!TextUtils.isEmpty(json)){
      try {
        return JsonKit.GSON.fromJson(json,LocationModel.class);
      }catch (Throwable e){
        Tools.getCache().remove(LAST_LOCATION);
        e.printStackTrace();
      }
    }
    return null;
  }

  public LocationModel getCurrentLocation() {
    if (currentLocation == null){
      currentLocation = getFromCache();
    }
    return currentLocation;
  }

  public void distanceBetween(double endLatitude, double endLongitude,float[] results){
    if(currentLocation != null){
      Location.distanceBetween(currentLocation.latitude,currentLocation.longitude,endLatitude,endLongitude,results);
    }
  }

  public void lazyLoad(){
    if(currentLocation == null){
      loadLocation();
    }
  }


  private AmapCityModel getAmpCityInfo(final String city){
    DistrictSearch search = new DistrictSearch(context);

    DistrictSearchQuery query = new DistrictSearchQuery();
    query.setKeywords(city);//传入关键字
    query.setShowBoundary(false);//是否返回边界值
    search.setQuery(query);

    try {

      DistrictResult districtResult = search.searchDistrict();

      if (districtResult !=null){

        ArrayList<DistrictItem> district = districtResult.getDistrict();

        if (district != null && !district.isEmpty()){
          DistrictItem districtItem = district.get(0);
          AmapCityModel cityModel = new AmapCityModel();
          cityModel.name = districtItem.getName();
          cityModel.adCode = districtItem.getAdcode();
          cityModel.cityCode = districtItem.getCitycode();
          cityModel.level = districtItem.getLevel();
          return cityModel;
        }
      }
    } catch (AMapException e) {
      e.printStackTrace();
    }
    return null;
  }


  public Single<Optional<AmapCityModel>> getCityInfo(final String city){
    return Single.concat(Single.fromCallable(new Callable<Optional<AmapCityModel>>() {
      @Override
      public Optional<AmapCityModel> call() throws Exception {
        return Optional.ofNullable(getAmpCityInfo(city));
      }
    }),Single.fromCallable(new Callable<Optional<AmapCityModel>>() {
      @Override
      public Optional<AmapCityModel> call() throws Exception {
        return Optional.ofNullable(getAmpCityInfo(city+"市"));
      }
    })).filter(new Predicate<Optional<AmapCityModel>>() {
      @Override
      public boolean test(Optional<AmapCityModel> amapCityModelOptional) throws Exception {
        AmapCityModel cityModel = amapCityModelOptional.orNull();

        return cityModel != null && (TextUtils.equals(cityModel.level,"city") || TextUtils.equals(cityModel.level,"province"));
      }
    }).firstOrError();
  }

  public interface OnRequestLocationCallback{

    void onGetLocation(LocationModel locationModel);

    void onError(String msg);

  }

}
